
#ifndef _AIRLINERESERVATION_H_20111201
#define _AIRLINERESERVATION_H_20111201

#include <vector>
#include <list>

#include "RecordManager.h"

#include "FlightRecord.h"
#include "BookingRecord.h"
#include "CustomerRecord.h"
#include "UserRecord.h"

#define SEARCH_BY_BOOKING_NUMBER 1
#define SEARCH_BY_NAME 2

#define SEARCH_BY_FLIGHT_NUMBER 1
#define SEARCH_BY_DESTINATION 2

#define ANSWER_YES "y"
#define ANSWER_NO "n"

#define USER_GUIDE_COMMAND "notepad help.txt"

#define MAIN_MENU_COMMAND "quit"

#define ADMIN_USER_MENU 0
#define REGULAR_USER_MENU 1

namespace AirlineRes
{

class AirlineReservationSystem
{
public:
  AirlineReservationSystem();
  ~AirlineReservationSystem(){};

  /// Called to initialised the system.
  void Init();
  /// Called to start the system, i.e. begin responding interactively to user input.
  void Run();
  /// Called after the user has exited the system.
  void Shutdown();

private:
  bool m_userIsAdmin;

  /// Represents a return result for an interface menu function.
  enum InterfaceResult
  {
    InterfaceResult_Success,    // Operation succeeded.
    InterfaceResult_Abort,      // User wants to exit the menu (so go up one level in the menu hierarchy).
    InterfaceResult_Unknown,    // This should never be returned by a function in theory.
    InterfaceResult_Logout,
    InterfaceResult_NumResults
  };

  /// Function for displaying a menu and retrieving a numeric value representing the desired menu option from the user.
  /// @return -1 if the input was invalid, a positive integer otherwise.
  int GetOptionChoice( std::string const& _menuDesc );
  /// Displays a prompt accepting a Y/N response from the user.
  /// @return -1 if the input was invalid, 0 for 'no', 1 for 'yes'
  int GetYesNoChoice( std::string const& _prompt );

  /// Prompts the user to confirm their action before it is executed by displaying a Y/N prompt until a valid input is received.
  /// @return true if the user confirmed, i.e. responded 'y'/'Y'.
  bool ConfirmAction();

  int GetOptionChoiceWithoutPrintingMenu( std::string input );

  /// Allows the user to attempt to login to the system and sets m_userIsAdmin appropriately if they are successful.
  ///
  /// @return InterfaceResult_Success if the user provides valid credentials,
  ///         InterfaceResult_Abort if the user aborts the login attempt.
  InterfaceResult LoginScreen();

  /// Determine whether or not the supplied credentials are valid, i.e. user exists and password is correct.
  ///
  /// @return True if valid, false if not valid.
  bool UserCredentialsValid( std::string const& _username, std::string const& _password );

  enum AdminSubMenuOption
  {
    AdminSubMenuOption_Exit,
    AdminSubMenuOption_Add,
    AdminSubMenuOption_Edit,
    AdminSubMenuOption_Delete,
    AdminSubMenuOption_NumOptions,
    AdminSubMenuOption_Unknown = -1
  };

  InterfaceResult AdminMenu();
  void AdminCustomerMenu( AdminSubMenuOption _option );
  void AdminFlightMenu( AdminSubMenuOption _option );
  void AdminBookingMenu( AdminSubMenuOption _option );
  void AdminUserMenu( AdminSubMenuOption _option );

  void AddUser();

  InterfaceResult RegularUserMenu();
  void RegularUserBookingProcedure();
  void RegularUserCancellationMenu();
  void RegularUserFlightEnquiryMenu();
  void RegularUserPassengerEnquiryMenu();
  
  //Passenger Enquiry functions
  void RegularUserPassengerEnquirySearch(int);
  void RegularUserPassengerEnquirySearchByBookingNumber();
  void RegularUserPassengerEnquirySearchByName();
  void RegularUserPassengerEnquiryCustomerSelectionList(std::vector <std::string>);
  void RegularUserPassengerEnquiryOutput(int, std::string, std::string);
  std::string RegularUserPassengerEnquiryOutputGetFlightCode(int);
  TimeDate RegularUserPassengerEnquiryOutputGetFlightTimeDate(int);
  void RegularUserPassengerEnquiryAsk();
  std::string GetBookingClassString( int );
  std::string GetBookingStatusString( int );
  void RegularUserFlightEnquiryOutput(std::string);

  void RegularUserFlightEnquirySearchByDestination();

  /// Confirms the logout action of the user.   
  ///
  /// @param menu The main menu of the user: ADMIN_USER_MENU or REGULAR_USER_MENU
  void LogoutConfirmation(int);

  /// Confirms the exit of the user.   
  ///
  /// @param menu The main menu of the user: ADMIN_USER_MENU or REGULAR_USER_MENU
  void ExitConfirmation(int);

  /// Displays the help document.
  void LaunchHelp();

  /// Check if the the string passed to the function is the
  /// command for returning the user back to main menu.
  ///
  /// @param menu The main menu of the user: ADMIN_USER_MENU or REGULAR_USER_MENU
  /// @param user_input The user input.
  void CheckReturningToMainMenu( int menu, std::string user_input );

  //Flight Enquiry Functions
  void RegularUserFlightEnquirySearch(int);
  void RegularUserFlightEnquirySearchByFlightNumber();
  void RegularUserFlightEnquiryAsk();

  /// Check to ensure the string passed to the function is valid answer to a 
  /// Yes/No question.  The format required is "Y" or "N".
  ///
  /// @param user_input  The users answer to the Yes/No question.
  ///
  /// @return A boolean value: True if the string is "Y" or "N", else false.
  bool IsYesNoChoiceValid( std::string user_input );

  /// Gets the flight ID choice from the user and ensure that the user input 
  /// is numerical and valid by calling IsFlightIDValid().
  ///
  /// @return An integer value which represents the Flight ID
  int GetFlightIDChoice();

  /// Check to ensure a given Flight ID is valid.  This is done by search the 
  /// set of flights on the system and attempting to match the given Flight ID.
  ///
  ///@param flight_id    The Flight ID read frm the user
  ///
  ///@return A boolean value: True if the Flight ID is valid, else false.
  bool IsFlightIDValid( int flight_id );

  /// Gets a destination value from the user and checks ot ensure that the destination entered
  /// contains only alphanumeric values.
  ///
  /// @return A string which represents the destination chosen by the user.
  std::string GetBookingDestination();

  /// Gets the subset of flights from the set of all flights by matching the destination
  ///
  /// @param destination    The destination for the flight as chosen by the user.
  ///
  /// @return A list of Flight Records which match the destination value.
  std::list<FlightRecord const*> GetFlightShortList( std::string destination );

  /// Prints a table of flight details
  ///
  /// @param shortlist  A list of flight records to print.
  void DisplayFlights( std::list<FlightRecord const*> const& shortlist );

  /// Prompts the user to decide whether they wish to book on the alternative class.  Thi function 
  /// be used when the intial class request cannot be granted as that class is full.
  ///
  /// @return A boolean value: true if the user wishes to book on the alternative class, else false.
  bool WantToBookAlternativeClass();

  /// Prompts the user to decided whether they wish to reserve a seat for a flight.  Will be
  /// used when the initial class choice is full and either the alternatie class choice is full
  /// or they do not wish to book on the alternative class.
  ///
  /// @return A boolean value: true if the user wishes to reserve a seat, else false.
  bool WantToBookReserve();

  /// Changes the given booking class to the alternative booking class.
  /// 
  /// @param booking_class  The original booking class to be changed.
  ///
  /// @return A booking class value which is the alternative to the booking class given.
  BookingRecord::BookingClass SwitchBookingClass( BookingRecord::BookingClass booking_class );

  /// Prompts the user to input a value for whether or not they have already registered as a customer.  
  /// Includes validation on the Y/N input using the ValidateYesNoInput() function.
  ///
  /// @return A boolean value: true if the customer has already registered, else false.
  bool AlreadyRegistered();

  /// Gets a value for the customer ID chocie from the user.  this function will be called
  /// after a list of customers has been displayed to the user and the customer is required to 
  /// select which customer information relted to them.
  ///
  /// @return  An integer value which represents a Customer ID for the chosen customer.
  int GetCustomerIDChoice();

  /// Check to see if the Customer ID passed is valid by checking for a matching Customer
  /// ID in the set of Customer records held on the system.
  ///
  /// @param  customer_id    The Customer ID which would be input from the user.
  ///
  /// @return    A boolean value: true if the Customer ID is valid, else false.
  bool IsCustomerIDValid( int customer_id );

  /// Get a value for the customer surname from the user.  This function would be called if the user has indicated that 
  /// they are already registered on the system and are now required to enter a surname through which they can be 
  /// indentified.
  ///
  /// @return    A string representing the customer surname given by the user.
  std::string GetCustomerSurname();

  /// Gets a subset of customers from the custoemr set where the surname matches the 
  /// Last Name stored in the customer record.
  ///
  /// @param  surname    The surname given by the user.
  ///
  /// @return  A list of Customer Record which contain a Last Name which matches the surname passed.
  std::list<CustomerRecord const*> GetCustomerList( std::string surname );

  /// Prints a table of customer details.
  ///
  /// @param  shortlist  The list of customers to print.
  void DisplayCustomers( std::list<CustomerRecord const*> const& shortlist );


  // Admin Booking Functions
    
  /// Adds a customer to the Customer Set by prompting the user for customer
  /// details, validating thier format and then storing the information.
  ///
  /// @return The customer ID of the new customer which has been added.
  int AddCustomerProcedure();

  std::string GetCustomerFirstName();
  std::string GetCustomerLastName();
  std::string GetCustomerPassportNumber();
  std::string GetCustomerDOB();
  std::string GetCustomerEmail();
  std::string GetCustomerPhoneNumber();

  /// Adds a boooking to the Booking Set by prompting the user for booking
  /// details, validating thier format and then storing the information.
  void AddBookingProcedure();

  int GetBookingFlightID();
  int GetBookingCustomerID();
  BookingRecord::BookingStatus GetBookingStatus();
  BookingRecord::BookingClass GetBookingClass();

  /// Adds a flight to the Flight Set by prompting the user for flight
  /// details, validating thier format and then storing the information.
  void AddFlightProcedure();

  /// Adds a user to the User Set by prompting the user for user
  /// details, validating thier format and then storing the information.
  void AddUserProcedure();

  /// The function checks to see whether there is space on a given flight, in a 
  /// given class as specififed by the parameters of the function.
  ///
  /// @param flight_id      The flight Id of the flight to be checked.
  /// @param booking_class  The booking class to be checked.
  ///
  ///@return A boolean value indicating whether there is space.
  bool IsSpace( int flight_id, BookingRecord::BookingClass booking_class );

  /// Parses an string taken from a user input, and converts that into 
  /// a boolean. Y becomes true, anything else becomes false.
  ///
  /// @param admin_string        The user input value for whether th user is an admin
  ///
  /// @return True is admin_string = "Y", else False.
  bool ParseAdmin( std::string admin_string );


  RecordManager<FlightRecord>   m_flightRecords;
  RecordManager<BookingRecord>  m_bookingRecords;
  RecordManager<CustomerRecord> m_customerRecords;
  RecordManager<UserRecord>     m_userRecords;

  std::string const c_filePathFlights;
  std::string const c_filePathBooking;
  std::string const c_filePathCustomer;
  std::string const c_filePathUser;
};

} // namespace AirlineRes

#endif // _AIRLINERESERVATION_H_20111201
